package com.rp.download.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Splitter;
import com.rp.download.util.ExcelUtils;
import com.rp.download.vo.ExeclVo;
import com.rp.download.vo.ExportRequestVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@RestController
@Slf4j
public class ExportController {

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;


    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 数据导出接口
     * @param vo
     * @param response
     * @throws Exception
     */
    @PostMapping("/exportExcel")
    public void exportExcel(ExportRequestVo vo, HttpServletResponse response) throws Exception {

        //生产保存数据的redis - key :用户保存每行记录数
        String uuid = UUID.randomUUID().toString();

        //总记录数
        Integer total = vo.getTotal();
        if (total == null || total <= 0) {
            throw new RuntimeException("总记录数不能为空");
        }

        //请求地址
        String urlPath = vo.getUrl();
        if (StringUtils.isBlank(urlPath)) {
            throw new RuntimeException("地址不能为空");
        }

        //每次请求的qid
        String qid = getParam(urlPath, "qid");

        //记录总共要请求多少次服务获取数据信息
        int totalPage = total % 500 == 0 ? (total / 500) :(total / 500 + 1);

        //保存要请求的地址路径
        List<String> listVo = new ArrayList<>();

        for (int i = 0; i < totalPage; i++) {
            int a = 0;
            int b = 0;
            if (i == totalPage - 1) {
                a = i * 500 + 1;
                b = total;
            } else {
                a = i * 500 + 1;
                b = (i + 1) * 500;
            }
            //替换请求地址的参数
            String mark_from = replaceAccessTokenReg(urlPath, "mark_from", String.valueOf(a));
            String mark_to = replaceAccessTokenReg(mark_from, "mark_to", String.valueOf(b));
            String pathMember = replaceAccessTokenReg(mark_to, "qid", String.valueOf(Integer.valueOf(qid) + i));
            listVo.add(pathMember);
        }
        log.info("远程请求地址集合 listVo = {},size = {}", JSON.toJSONString(listVo),listVo.size());


        //遍历地址进行远程请求
        if (listVo.size() > 0) {

            final CountDownLatch countDownLatch = new CountDownLatch(listVo.size());

            for (int k = 0; k < listVo.size(); k++) {

                String urlString = listVo.get(k);

                CompletableFuture.runAsync(() -> {
                    try {
                        getList(urlString, uuid);
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("远程请求失败:{}",e.getMessage());
                    } finally {
                        countDownLatch.countDown();
                    }
                }, threadPoolExecutor);
            }

            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //从redis中获取所有的记录数
        List<String> listb = redisTemplate.opsForList().range(uuid, 0, -1);

        List<ExeclVo> listResult = new ArrayList<>(listb.size());
        for (int i = 0; i < listb.size(); i++) {
            if(StringUtils.isBlank(listb.get(i))){
                continue;
            }
            String[] split = new String[]{
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", "", "", "", "",
                    "", "", "", "", "", "", ""
            };

            String[] strArr = listb.get(i).split("\t");
            System.out.println("*************************" + strArr.length);

            for (int j = 0; j < strArr.length; j++) {
                split[j] = strArr[j].trim();
            }

            ExeclVo execlVo = new ExeclVo(
                    split[0].trim(),
                    split[1].trim(),
                    split[2].trim(),
                    split[3].trim(),
                    split[4].trim(),
                    split[5].trim(),
                    split[6].trim(),
                    split[7].trim(),
                    split[8].trim(),
                    split[9].trim(),
                    split[10].trim(),
                    split[11].trim(),
                    split[12].trim(),
                    split[13].trim(),
                    split[14].trim(),
                    split[15].trim(),
                    split[16].trim(),
                    split[17].trim(),
                    split[18].trim(),
                    split[19].trim(),
                    split[20].trim(),
                    split[21].trim(),
                    split[22].trim(),
                    split[23].trim(),
                    split[24].trim(),
                    split[25].trim(),
                    split[26].trim(),
                    split[27].trim(),
                    split[28].trim(),
                    split[29].trim(),
                    split[30].trim(),
                    split[31].trim(),
                    split[32].trim(),
                    split[33].trim(),
                    split[34].trim(),
                    split[35].trim(),
                    split[36].trim(),
                    split[37].trim(),
                    split[38].trim(),
                    split[39].trim(),
                    split[40].trim(),
                    split[41].trim(),
                    split[42].trim(),
                    split[43].trim(),
                    split[44].trim(),
                    split[45].trim(),
                    split[46].trim(),
                    split[47].trim(),
                    split[48].trim(),
                    split[49].trim(),
                    split[50].trim(),
                    split[51].trim(),
                    split[52].trim(),
                    split[53].trim(),
                    split[54].trim(),
                    split[55].trim(),
                    split[56].trim(),
                    split[57].trim(),
                    split[58].trim(),
                    split[59].trim(),
                    split[60].trim(),
                    split[61].trim(),
                    split[62].trim(),
                    split[63].trim(),
                    split[64].trim(),
                    split[65].trim(),
                    split[66].trim()
            );
            listResult.add(execlVo);
        }

        //7.3 Excel名称
        String fileName = uuid + ".";

        try {
            ExcelUtils.exportExcel(response, fileName, listResult, ExeclVo.class);
        } catch (IOException e) {
            log.error("导出Excel异常:", e.getMessage());
            e.printStackTrace();
            try {
                response.setContentType("text/html; charset=UTF-8");//注意text/html，和application/html
                response.getWriter().print("<html><body><script type='text/javascript'>alert('下载Excel数据异常！');</script></body></html>");
                response.getWriter().close();
                return;
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }

    }


    public void getList(String urlPath, String uuid) throws Exception {
        URL url = new URL(urlPath);
        HttpURLConnection http = (HttpURLConnection) url.openConnection();
        http.setConnectTimeout(6000);
        // 设置 User-Agent 避免被拦截
        http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
        String contentType = http.getContentType();
        log.info("contentType: " + contentType);
        // 获取文件大小
        long length = http.getContentLengthLong();
        log.info("文件大小：" + (length / 1024) + "KB");
        // 获取文件名
        InputStream inputStream = http.getInputStream();

        //============================

//        String path = "/Users/rp/Downloads/aabb.txt";
//        FileInputStream inputStream = new FileInputStream(path);
        // 防止路径乱码   如果utf-8 乱码  改GBK     eclipse里创建的txt  用UTF-8，在电脑上自己创建的txt  用GBK
        InputStreamReader isr = new InputStreamReader(inputStream, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String line = "";
        ListOperations listOperations = redisTemplate.opsForList();
        while ((line = br.readLine()) != null) {

            if (line.contains("PT") && line.contains("AU") && line.contains("BA") && line.contains("GP")) {
                continue;
            }
            listOperations.rightPush(uuid, line);
            // ﻿PT	AU	BA	AU	GP	AF	BF	CA	TI	SO
            // SE	BS	LA	DT	CT	CY	CL	SP	HO	DE	ID
            // AB	C1	RP	EM	RI	OI	FU	FX	CR	NR	TC
            // Z9	U1	U2	PU	PI	PA	SN	EI	BN	J9	JI
            // PD	PY	VL	IS	PN	SU	SI	MA	BP	EP	AR
            // DI	D2	EA	PG	WC	SC	GA	UT	PM	OA	HC
            // HP	DA
        }
        redisTemplate.expire(uuid, 60 * 10, TimeUnit.SECONDS);
        br.close();
        isr.close();
        inputStream.close();
    }


    /**
     * 正则替换
     *
     * @param url
     * @param name
     * @param accessToken
     * @return
     */
    public static String replaceAccessTokenReg(String url, String name, String accessToken) {
        if (StringUtils.isNotBlank(url) && StringUtils.isNotBlank(accessToken)) {
            url = url.replaceAll("(" + name + "=[^&]*)", name + "=" + accessToken);
        }
        return url;
    }

    public static String getParam(String url, String name) {
        String params = url.substring(url.indexOf("?") + 1, url.length());
        Map<String, String> split = Splitter.on("&").withKeyValueSeparator("=").split(params);
        return split.get(name);
    }
}
